/***********************************************************************************
Copy right:	    hqyj Tech.
Author:         jiaoyue
Date:           2023.07.01
Description:    http请求处理
***********************************************************************************/

#include <sys/types.h>
#include <sys/socket.h>
#include "custom_handle.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <stdint.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include "msg_queue_peer.h"
#include "shmem.h"

#define KB 1024
#define HTML_SIZE (64 * KB)

// 普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
                  "Connection: close\r\n"

int *shmemNum = NULL;             // 共享内存的数据量
struct std_node *shmemStd = NULL; // 共享内存中首个元素地址

union val_t
{
    int b_val;   // bool类型存储空间
    int i_val;   // 整形值存储空间
    float f_val; // 浮点值存储空间
};

typedef struct msg
{
    long device_type; // 消息类型，用于区分32与modbus设备
    int key;
    union val_t val;
} msg_t;

typedef struct data1
{
    int key;
    int set;
    int type;
    union val_t val;
} Data;

struct data2
{
    Data temp; // 温度
    Data hum;  // 湿度
    Data tate; //
    Data time;
    Data fall;
    Data light;
    Data fan;
    Data air;
    Data buzzer;
    Data video;
    Data compass;
    Data step;
} value;

struct std_node
{
    int key;             // 唯一键值
    int type;            // 数据点类型
    int dev_type;        // 数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; // 变化上报后需要更新旧值
    union val_t new_val; // 从共享内存取出最新数据，放到new_val中
    int ret;             // 默认为-1，采集成功后设置为0，采集失败再置-1
};

static int handle_login(int sock, const char *input)
{
    char reply_buf[HTML_SIZE] = {0};
    char *uname = strstr(input, "username=");
    uname += strlen("username=");
    char *p = strstr(input, "password");
    *(p - 1) = '\0';
    printf("username = %s\n", uname);

    char *passwd = p + strlen("password=");
    printf("passwd = %s\n", passwd);

    if (strcmp(uname, "admin") == 0 && strcmp(passwd, "admin") == 0)
    {
        sprintf(reply_buf, "<script>localStorage.setItem('usr_user_name', '%s');</script>", uname);
        strcat(reply_buf, "<script>window.location.href = './index.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }
    else
    {
        printf("web login failed\n");

        //"用户名或密码错误"提示，chrome浏览器直接输送utf-8字符流乱码，没有找到太好解决方案，先过渡
        char out[128] = {0xd3, 0xc3, 0xbb, 0xa7, 0xc3, 0xfb, 0xbb, 0xf2, 0xc3, 0xdc, 0xc2, 0xeb, 0xb4, 0xed, 0xce, 0xf3};
        sprintf(reply_buf, "<script charset='gb2312'>alert('%s');</script>", out);
        strcat(reply_buf, "<script>window.location.href = './temp_login.html';</script>");
        send(sock, reply_buf, strlen(reply_buf), 0);
    }

    return 0;
}

static int handle_add(int sock, const char *input)
{
    int number1, number2;

    // input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"data1=%ddata2=%d\"", &number1, &number2);
    printf("num1 = %d\n", number1);

    char reply_buf[HTML_SIZE] = {0};
    printf("num = %d\n", number1 + number2);
    sprintf(reply_buf, "%d", number1 + number2);
    printf("resp = %s\n", reply_buf);
    send(sock, reply_buf, strlen(reply_buf), 0);

    return 0;
}

static int get_info(int sock, const char *input)
{
    // key_t key;
    // while ((key = ftok("/home/hq/project/project_demo/", 'j')) == -1)
    //     ;
    // int shmid; // 共享内存

    // // 创建或打开共享内存
    // // shmid = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0666);
    // while ((shmid = shmget(key, 256, IPC_CREAT | IPC_EXCL | 0666)) <= 0)
    // {
    //     if (errno == EEXIST) // 如果已存在则直接打开共享内存
    //     {
    //         shmid = shmget(key, 256, 0666); // 直接打开共享内存
    //         break;
    //     }
    // }
    // // 映射共享内存
    // uint16_t *p = NULL;
    // while ((p = (uint16_t *)shmat(shmid, NULL, 0)) == (uint16_t *)-1)
    //     ;

    // char reply_buf[HTML_SIZE] = {0};
    // sprintf(reply_buf, "%d %d %d %d", p[0], p[1], p[2], p[3]);
    // // reply_buf[strlen(reply_buf)] = '\0';

    // send(sock, reply_buf, strlen(reply_buf), 0);
    // p[4] = 0;

    // 建立共享内存
    struct shm_param para;
    if (shm_init(&para, "SHMEM", 512) < 0)
    {
        perror("init err");
        return 0;
    }
    shmemNum = shm_getaddr(&para);

    if (shmemNum == NULL)
    {
        perror("getaddr err");
        return 0;
    }
    shmemStd = (struct std_node *)(shmemNum + 1);

    char reply_buf[512] = {0};
    char str[256] = {0};

    for (int i = 0; i < 15; i++)
    {
        if (shmemStd[i].key == 301) // 体温
        {
            sprintf(str, "%d %.1f\n", shmemStd[i].key, shmemStd[i].new_val.f_val);
            strcat(reply_buf, str);
        }
        else if (shmemStd[i].key == 303) // 心率
        {
            sprintf(str, "%d %.1f\n", shmemStd[i].key, shmemStd[i].new_val.f_val);
            strcat(reply_buf, str);
        }
        else if (shmemStd[i].key == 312) // 步数
        {
            sprintf(str, "%d %d\n", shmemStd[i].key, shmemStd[i].new_val.i_val);
            strcat(reply_buf, str);
        }
        else if (shmemStd[i].key == 101) // 室内温度
        {
            sprintf(str, "%d %.1f\n", shmemStd[i].key, shmemStd[i].new_val.f_val);
            strcat(reply_buf, str);
        }
        else if (shmemStd[i].key == 102) // 室内湿度
        {
            sprintf(str, "%d %.1f", shmemStd[i].key, shmemStd[i].new_val.f_val);
            strcat(reply_buf, str);
        }
    }

    printf("%s\n", reply_buf);
    send(sock, reply_buf, strlen(reply_buf), 0);


    return 0;
}

static int set_info(int sock, const char *input)
{
    char *p = strstr(input, "set");
    p += strlen("set 10");

    msg_t msg;

    msg.device_type = 1;
    if (p[0] == '4')
        msg.key = 104;
    else if (p[0] == '5')
        msg.key = 105;
    else if (p[0] == '6')
        msg.key = 106;
    msg.val.b_val = p[1] - '0';

    msg_queue_send("MSG", &msg, sizeof(msg), 0);
    return 0;
}

/**
 * @brief 处理自定义请求，在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    // query_string不一定能用的到

    // 先处理登录操作
    if (strstr(input, "username=") && strstr(input, "password="))
    {
        return handle_login(sock, input);
    }
    // 处理求和请求
    else if (strstr(input, "data1=") && strstr(input, "data2="))
    {
        return handle_add(sock, input);
    }
    else if (strstr(input, "get")) // 获取数值
    {
        return get_info(sock, input);
    }
    else if (strstr(input, "set")) // 设置
    {
        return set_info(sock, input);
    }
    else // 剩下的都是json请求，这个和协议有关了
    {
        // 构建要回复的JSON数据
        const char *json_response = "{\"message\": \"Hello, client!\"}";

        // 发送HTTP响应给客户端
        send(sock, json_response, strlen(json_response), 0);
    }

    return 0;
}
